/// ZY_DRV_DISP_KEY_TM1618 driver
#include "CH58x_common.h"
#include "zqm_global.h"
#include "zqm_module.h"

#ifdef ZY_DRV_DISP_KEY_TM1628 // ZY_DRV_DISP_KEY_TM1618

// general codec functions----------------------------------------------------------------------------------
// led char code table: {char, code}
	//   AAA
	//  F   B
	//  F   B
	//   GGG
	//  E   C
	//  E   C
	//   DDD  H
static const uint8_t led_char_code_table[][2] = {
							// MASK -------------- | HG FE DCBA |
	{(uint8_t)'0', 0x3f},	// '0' --  ABCDEF   -- |    11 1111 | --
	{(uint8_t)'1', 0x06},	// '1' --   BC      -- |        11  | --
	{(uint8_t)'2', 0x5b},	// '2' --  AB DE G  -- |  1  1 1 11 | --
	{(uint8_t)'3', 0x4f},	// '3' --  ABCD  G  -- |  1    1111 | --
	{(uint8_t)'4', 0x66},	// '4' --   BC  FG  -- |  1 1   11  | --
	{(uint8_t)'5', 0x6d},	// '5' --  A CD FG  -- |  1 1  11 1 | --
	{(uint8_t)'6', 0x7d},	// '6' --  A CDEFG  -- |  1 11 11 1 | --
	{(uint8_t)'7', 0x07},	// '7' --  ABC      -- |        111 | --
	{(uint8_t)'8', 0x7f},	// '8' --  ABCDEFG  -- |  1 11 1111 | --
	{(uint8_t)'9', 0x6f},	// '9' --  ABCD FG  -- |  1 1  1111 | --
	{(uint8_t)'A', 0x77},	// 'A' --  ABC EFG  -- |  1 11  111 | --
	{(uint8_t)'a', 0x77},	// 'A' --  ABC EFG  -- |  1 11  111 | --
	{(uint8_t)'B', 0x7c},	// 'b' --    CDEFG  -- |  1 11 11   | --
	{(uint8_t)'b', 0x7c},	// 'b' --    CDEFG  -- |  1 11 11   | --
	{(uint8_t)'C', 0x39},	// 'C' --  A  DEF   -- |    11 1  1 | --
	{(uint8_t)'c', 0x58},	// 'c' --     DE G  -- |  1  1 1    | --
	{(uint8_t)'D', 0x5e},	// 'd' --   BCDE G  -- |  1  1 111  | --
	{(uint8_t)'d', 0x5e},	// 'd' --   BCDE G  -- |  1  1 111  | --
	{(uint8_t)'E', 0x79},	// 'E' --  A  DEFG  -- |  1 11 1  1 | --
	{(uint8_t)'e', 0x79},	// 'E' --  A  DEFG  -- |  1 11 1  1 | --
	{(uint8_t)'F', 0x71},	// 'F' --  A   EFG  -- |  1 11    1 | --
	{(uint8_t)'f', 0x71},	// 'F' --  A   EFG  -- |  1 11    1 | --
	{(uint8_t)'H', 0x76},	// 'H' --   BC EFG  -- |  1 11  11  | --
	{(uint8_t)'i', 0x30},	// '1' --      EF   -- |    11      | --
	{(uint8_t)'L', 0x38},	// 'L' --     DEF   -- |    11 1    | --
	{(uint8_t)'n', 0x54},	// 'n' --    C E G  -- |  1  1  1   | --
	{(uint8_t)'o', 0x5c},	// 'o' --    CDE G  -- |  1  1 11   | --
	{(uint8_t)'P', 0x73},	// 'P' --  AB  EFG  -- |  1 11   11 | --
	{(uint8_t)'r', 0x50},	// 'r' --      E G  -- |  1  1      | --
	{(uint8_t)'S', 0x6d},	// 's' --  A C  FG  -- |  1 1   1 1 | --
	{(uint8_t)'s', 0x6d},	// 's' --  A C  FG  -- |  1 1   1 1 | --
    {(uint8_t)'T', 0x78},	// 't' --  A   EF   -- |    11    1 | --
	{(uint8_t)'t', 0x78},	// 't' --     DEFG  -- |  1 11 1    | --
	{(uint8_t)'-', 0x40},	// '-' --        G  -- |  1         | --
	{(uint8_t)' ', 0x00},	// ' ' --        G  -- |            | --
	{(uint8_t)'/', 0x52},	// '/' --   B  E G  -- |  1  1   1  | --
	{(uint8_t)'Z', 0xff},	// 'Z' --  ABCDEFGH -- | 11 11 1111 | --
	{(uint8_t)'U', 0x3e},	// '0' --   BCDEF   -- |    11 111  | --
	{(uint8_t)'u', 0x3e},	// '0' --   BCDEF   -- |    11 111  | --
	{(uint8_t)'\'',0x02},	// ''' --   B       -- |        1   | --
	{(uint8_t)',', 0x04},	// ',' --    C      -- |       1    | --
};
// led icon code table: {dig, seg}, seg = 0: not available in this type of diaplay module
#if (ZQ_DISPLAY_PANEL_TYPE == DPT_SPLIT_1)
const uint8_t led_icon_code_table[LED_ICON_NUM][2] = {
    {0, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
    {0, 0x04}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
    {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
    {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x02},  		// disp_item_drip, disp_item_x, disp_item_dot, disp_item_minus
};
#elif (ZQ_DISPLAY_PANEL_TYPE == DPT_SPLIT_2)
const uint8_t led_icon_code_table[LED_ICON_NUM][2] = {
    {1, 0x80}, {2, 0x80}, {0, 0x00}, {0, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
    {0, 0x04}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
    {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
    {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x80},  		// disp_item_drip, disp_item_x, disp_item_dot, disp_item_minus
};
#elif (ZQ_DISPLAY_PANEL_TYPE == DPT_SPLIT_1x)
const uint8_t led_icon_code_table[LED_ICON_NUM][2] = {
    {1, 0x80}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_comp, disp_item_hot, disp_item_defrost, disp_item_lp,
    {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_lock, disp_item_alarm, disp_item_fan, disp_item_door,
    {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},			// disp_item_wifi, disp_item_4g, disp_item_battery, disp_item_bt,
    {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x80},  		// disp_item_drip, disp_item_x, disp_item_dot, disp_item_minus
};
#endif
extern char disp_buff[LED_ITEM_NUM][2];
uint8_t disp_memory[DISP_MEMORY_SIZE];	        // ICON1, 十, 个, 3位7段  或者  十, 个, 2位8段

// codec a display elements in the disp_buff to disp_memory
void LedCodecItem(disp_item_t item_no, uint8_t isOn)
{
	uint8_t code = 0;
	uint8_t dig = 0;
	// icon type items
	if (item_no < LED_ICON_NUM) {
		dig = led_icon_code_table[item_no][0];
		code = led_icon_code_table[item_no][1];
		isOn = (disp_buff[item_no][0]) ? isOn : 0;
	}
	// char type items
	else if (item_no < LED_ITEM_NUM) {
		dig = disp_item_d_start + (item_no - LED_ICON_NUM); 
		for (int i = 0; i < (sizeof(led_char_code_table) / sizeof(led_char_code_table[0])); i++) {
			if (disp_buff[item_no][0] == led_char_code_table[i][0]) {
				code = led_char_code_table[i][1];
				break;
			}
		}
		disp_memory[dig] &= 0x80; // clear 0-6 seg buf, 保留第7 seg, 这可能是. 或者 - 等符号 .
	}
	if (code != 0) // code = 0 is not available
		disp_memory[dig] = (isOn) ? (disp_memory[dig] | code) : (disp_memory[dig] & (~code));
	return;
}

#ifndef ZQ_SIMULATOR
// TM1628 driver functions -----------------------------------------------------------------------------------------------
// period = 4us
static inline void SpiCS(int sel)
{
    (sel) ? (GPIO_SetBits(zy_ios.dis_stb)) : (GPIO_ResetBits(zy_ios.dis_stb));
    DelayUs(2);
}
static inline void SpiClk(void)
{
    // 沿读写操作
    GPIO_ResetBits(zy_ios.dis_clk);
    DelayUs(2);
    GPIO_SetBits(zy_ios.dis_clk);
    DelayUs(2);
}
// write a byte
static void SpiWriteByte(uint8_t date)
{
    // DelayUs(8);
    DelayUs(2);
    for (int i = 0; i < 8; date = date >> 1, i++) {
        (date & 1) ? GPIO_SetBits(zy_ios.dis_dio) : GPIO_ResetBits(zy_ios.dis_dio);
        SpiClk();
    }
}
// read a byte
uint8_t SpiReadByte(void)
{
    uint8_t data = 0;
    // DelayUs(8);
    DelayUs(2);
    for (int i = 0; i < 8; i++) {
        SpiClk();
        data |= GPIO_ReadPortPin(zy_ios.dis_dio) ? (1 << i) : 0;
    }
    return data;
}
// switch tm1618 to display mode
void TM1618SwitchWriteMode(void)
{
    GPIO_ModeCfg(zy_ios.dis_stb, GPIO_ModeOut_PP_5mA);
    GPIO_ModeCfg(zy_ios.dis_clk, GPIO_ModeOut_PP_5mA);
    GPIO_ModeCfg(zy_ios.dis_dio, GPIO_ModeOut_PP_5mA);
}
// switch tm1618 to key scan mode
void TM1618SwitchReadMode(void)
{
    GPIO_ModeCfg(zy_ios.dis_stb, GPIO_ModeOut_PP_5mA);
    GPIO_ModeCfg(zy_ios.dis_clk, GPIO_ModeOut_PP_5mA);
    GPIO_ModeCfg(zy_ios.dis_dio, GPIO_ModeIN_PD);
}
void TM1618Command(uint8_t com)
{
    // DelayUs(5);
    DelayUs(4);
    SpiCS(1);
    SpiCS(0);
    SpiWriteByte(com);
}

// Display and key driver functions----------------------------------------------------------------------------------
void DrvDispKeyInit(void)
{
   	ZQLOG("tm1628 init...");
}
#if (ZQ_DISPLAY_PANEL_TYPE == DPT_SPLIT_1 || ZQ_DISPLAY_PANEL_TYPE == DPT_SPLIT_2)
// display 3-digit * 7-seg, lightLevel 0-7
void DrvDisplay(uint8_t brightness)
{
    //unsigned short digit[];
    TM1618SwitchWriteMode();
    TM1618Command(0x01);   //set dismode 5-digit*12-seg, in fact, only use 3 digital, 7 seg. 
    TM1618Command(0x40);   //auto address++ write
    TM1618Command(0xc0);   //display addr 0x00
    for (int i = 0; i < DISP_MEMORY_SIZE; i++) {
        SpiWriteByte(disp_memory[i]);
        SpiWriteByte(0);
    }
    TM1618Command(0x88 + (brightness & 0x07));   //display on
    SpiCS(1);
}
#elif (ZQ_DISPLAY_PANEL_TYPE == DPT_SPLIT_1x)
// display 2-digit * 7-seg, lightLevel 0-7
void DrvDisplay(uint8_t brightness)
{
    //unsigned short digit[];
    TM1618SwitchWriteMode();
    TM1618Command(0x01);   //set dismode 5-digit*12-seg, in fact, only use 3 digital, 7 seg. 
    TM1618Command(0x40);   //auto address++ write
    TM1618Command(0xc0);   //display addr 0x00
    for (int i = 0; i < DISP_MEMORY_SIZE; i++) {
        SpiWriteByte(disp_memory[i]);
        SpiWriteByte(0);
    }
    TM1618Command(0x88 + (brightness & 0x07));   //display on
    SpiCS(1);
}
#endif

// Key Functions -----------------------------------------------------------------------------------------------
// return 2 key, bit1 = key1...bit0 = key2, 
uint8_t DrvReadKeys(void)
{
    uint8_t key = 0;
    uint8_t buf[3];
    TM1618SwitchWriteMode();
    TM1618Command(0x42);    //read key
    TM1618SwitchReadMode();
    mDelayuS(80*3);          // 1628 驱动这里要等待key扫描, 按照规格书, 大概每66us一个键, 这里冗余配置80us/key
    for (int i = 0; i < 3; i++) {  // read 3 byte
        buf[i] = SpiReadByte();
        // SpiClk();
    }
    SpiCS(1);
    // hardware set=buf[0]&0x01, switch=buf[0]&0x04, xxx=buf[1]&0x01 
	// 生成key，依据ZQ_KEY_ENUM排序 bit(ZQ_KEY_SET) = SET, bit(ZQ_KEY_PLUS) = PLUS, bit(ZQ_KEY_MINUS) = MINUS, 
    key |= (buf[0] & 0x01);
    key |= (buf[0] & 0x08) >> 2;
    key |= (buf[1] & 0x01) << 2;
    if (dbg_key != 0)  // 有dbg模拟key产生, 优先处理
        return dbg_key;
    else
        return key;
}

#endif // ZQ_SIMULATOR
#endif // ZY_DRV_DISP_KEY_TM1618